/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.view.panels;

import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.connect5.intervals.BasicDoubleInterval;
import org.jfonia.connect5.numerical.DoubleMaxRelation;
import org.jfonia.connect5.numerical.UnidirectionalDoubleSumRelation;
import org.jfonia.connect5.relations.Equal;
import org.jfonia.constants.ViewConstants;
import org.jfonia.view.main.LeadSheet;
import org.jfonia.view.main.MainFrame;
import org.jfonia.view.main.Project;
import org.jfonia.notation.Notation;
import org.jfonia.view.relations.DoubleInversionRelation;
import org.jfonia.view.scribbles.ScribblePanel;

/**
 *
 * @author Rik Bauwens
 */
public class ProjectPanel extends JPanel implements Observer, MouseListener
{
        private MainFrame parent;
        private LeadSheetPanel leadSheetPanel;
        private ScribblePanel scribblePanel;

        public ProjectPanel(MainFrame parent, Project project)
        {
                super();
                this.parent = parent;
                project.addObserver(this);
                setBackground(ViewConstants.MAIN_BACKGROUND_COLOR);
                addMouseListener(this);

                //Nodes
                MutableValueNode<Double> preferredWidthNode = new BasicValueNode<Double>(0.0);
                preferredWidthNode.addObserver(new Observer()
                {
                        public void onNotify(Object source)
                        {
                                MutableValueNode<Double> preferredWidthNode = (MutableValueNode<Double>) source;
                                setBounds(getX(), getY(), preferredWidthNode.getValue().intValue(), getHeight());
                                setPreferredSize(new Dimension(preferredWidthNode.getValue().intValue(), getHeight()));
                        }
                });
                MutableValueNode<Double> preferredHeightNode = new BasicValueNode<Double>(0.0);
                preferredHeightNode.addObserver(new Observer()
                {
                        public void onNotify(Object source)
                        {
                                MutableValueNode<Double> preferredHeightNode = (MutableValueNode<Double>) source;
                                setBounds(getX(), getY(), getWidth(), preferredHeightNode.getValue().intValue());
                                setPreferredSize(new Dimension(getWidth(), preferredHeightNode.getValue().intValue()));
                                //setMinimumSize(new Dimension(getWidth(), preferredHeightNode.getValue().intValue()));
                        }
                });
                final MutableValueNode<Double> xNode = new BasicValueNode<Double>(0.0);
                parent.getXNode().addObserver(new Observer(){
                        public void onNotify(Object source)
                        {
                                xNode.setValue(((MutableValueNode<Double>) source)
                                        .getValue() - getLocationOnScreen().x);
                        }
                });
                final MutableValueNode<Double> yNode = new BasicValueNode<Double>(0.0);
                parent.getYNode().addObserver(new Observer(){
                        public void onNotify(Object source)
                        {
                                yNode.setValue(((MutableValueNode<Double>) source)
                                        .getValue() - getLocationOnScreen().y);
                        }
                });

                //Panels
                setLayout(null);
                //Leadsheet panel
                BasicDoubleInterval leadSheetXInterval = new BasicDoubleInterval();
                BasicDoubleInterval leadSheetYInterval = new BasicDoubleInterval();
                new Equal<Double>(leadSheetXInterval.getDifferenceNode(), preferredWidthNode);
                leadSheetXInterval.setDifference(1); //Initial width
                leadSheetYInterval.setDifference(1); //Initial height
                leadSheetPanel = new LeadSheetPanel(leadSheetXInterval.getBeginNode(),
                                                    leadSheetYInterval.getBeginNode(),
                                                    leadSheetXInterval.getDifferenceNode(),
                                                    leadSheetYInterval.getDifferenceNode());
                add(leadSheetPanel);//, BorderLayout.NORTH);

                //Scribble panel
                BasicDoubleInterval scribbleXInterval = new BasicDoubleInterval();
                BasicDoubleInterval scribbleYInterval = new BasicDoubleInterval();
                new Equal<Double>(leadSheetXInterval.getBeginNode(), scribbleXInterval.getBeginNode());
                new Equal<Double>(leadSheetYInterval.getEndNode(), scribbleYInterval.getBeginNode());
                MutableValueNode<Double> minScribblePanelWidth = new BasicValueNode<Double>(ViewConstants.SCRIBBLE_PANEL_MIN_WIDTH);
                MutableValueNode<Double> minScribblePanelHeight = new BasicValueNode<Double>(ViewConstants.SCRIBBLE_PANEL_MIN_HEIGHT);
                //new DoubleMaxRelation(scribbleXInterval.getDifferenceNode(), minScribblePanelWidth);
                new DoubleMaxRelation(scribbleXInterval.getDifferenceNode(), leadSheetXInterval.getDifferenceNode());
                new DoubleMaxRelation(scribbleXInterval.getDifferenceNode(), parent.getWidthNode());
                //new DoubleMaxRelation(scribbleYInterval.getDifferenceNode(), minScribblePanelHeight);

                MutableValueNode<Double> projectPanelHeightNode = new BasicValueNode<Double>(0.0);
                MutableValueNode<Double> scribblePanelHeightNode = new BasicValueNode<Double>(0.0);
                MutableValueNode<Double> invertedNode = new BasicValueNode<Double>(0.0);
                new UnidirectionalDoubleSumRelation(parent.getHeightNode(), yNode, projectPanelHeightNode);
                new DoubleInversionRelation(leadSheetYInterval.getDifferenceNode(), invertedNode);
                new UnidirectionalDoubleSumRelation(projectPanelHeightNode, invertedNode, scribblePanelHeightNode);
                new DoubleMaxRelation(scribbleYInterval.getDifferenceNode(), scribblePanelHeightNode);

                new UnidirectionalDoubleSumRelation(leadSheetYInterval.getDifferenceNode(),
                                                    scribbleYInterval.getDifferenceNode(),
                                                    preferredHeightNode);
                scribblePanel = new ScribblePanel(scribbleXInterval.getBeginNode(),
                                                  scribbleYInterval.getBeginNode(),
                                                  scribbleXInterval.getDifferenceNode(),
                                                  scribbleYInterval.getDifferenceNode());
                add(scribblePanel);//, BorderLayout.SOUTH);

        }

        public LeadSheetPanel getLeadSheetPanel()
        {
                return leadSheetPanel;
        }
        
        private void setLeadSheet(LeadSheet leadSheet)
        {
                leadSheetPanel.setLeadSheet(leadSheet);
                if(leadSheet == null)
                        scribblePanel.setScribbles(null);
                else
                        scribblePanel.setScribbles(leadSheet.getScribbles());
                repaint();
        }

        public boolean hasLeadSheetFocus()
        {
                if(leadSheetPanel == null)
                        return false;
                return leadSheetPanel.hasFocus();
        }

        public boolean hasScribblesFocus()
        {
                if(scribblePanel == null)
                        return false;
                return scribblePanel.hasFocus();
        }

        public void onNotify(Object source)
        {
                setLeadSheet(Project.getInstance().getCurrentLeadSheet());
        }

        public void mouseClicked(MouseEvent e)
        {
                Notation.getInstance().clearSelectedElements();
                requestFocus();
        }

        public void mousePressed(MouseEvent e) {}

        public void mouseReleased(MouseEvent e) {}

        public void mouseEntered(MouseEvent e) {}

        public void mouseExited(MouseEvent e) {}
}
